home *** CD-ROM | disk | FTP | other *** search
/ Hottest 6 / Hottest 6 (1996)(PDSoft)[!].iso / software / videoutils / h-m / mandelsquare / mandelsquare-1.06.lha / PlayAnim.c < prev    next >
C/C++ Source or Header  |  1992-10-31  |  16KB  |  772 lines

  1. /*
  2. **    MandelSquare - AmigaDOS 2.0/3.0 Mandelbrot set explorer
  3. **
  4. **    PlayAnim.c, Routines to replay IFF-ANIM files
  5. **
  6. **    Copyright © 1991-1992 by Olaf `Olsen' Barthel
  7. **        All Rights Reserved
  8. */
  9.  
  10.     /* Animation module error codes, as returned by ValidateAnim(). */
  11.  
  12. enum    {        ANIMERR_WRONG_SEQUENCE=1,ANIMERR_NO_BODY,ANIMERR_WRONG_OPERATION,ANIMERR_NO_ANIM,
  13.             ANIMERR_MASKING,ANIMERR_IMAGE,ANIMERR_COMPRESSION,ANIMERR_NO_HEADER,ANIMERR_WRONG_SIZE,
  14.             ANIMERR_WRONG_MODE };
  15.  
  16.     /* Animation file list entry. */
  17.  
  18. struct AnimNode
  19. {
  20.     struct MinNode     Node;
  21.  
  22.     BitMapHeader    *BitMapHeader;
  23.     AnimationHeader    *AnimationHeader;
  24.  
  25.     APTR         Body;
  26.  
  27.     ULONG        *ViewModes,
  28.              Modes;
  29.  
  30.     struct Palette    *Palette;
  31. };
  32.  
  33.     /* Global flag. */
  34.  
  35. extern BYTE        Is39;
  36.  
  37.     /* In Double.c */
  38.  
  39. extern VOID        FreeDBI(struct DBI *Info);
  40. extern struct DBI *    AllocDBI(struct Screen *Screen);
  41. extern VOID        SwapDBI(struct DBI *Info,BYTE Copy);
  42. extern struct BitMap *    GetDBI(struct DBI *Info);
  43. extern VOID        PaletteDBI(struct DBI *Info,struct Palette *Palette);
  44. extern VOID        StartDBI(struct DBI *Info,ULONG Jiffies);
  45. extern VOID        WaitDBI(struct DBI *Info);
  46.  
  47.     /* In Palette.c */
  48.  
  49. extern VOID        FreePalette(struct Palette *Palette);
  50. extern struct Palette *    AllocPalette(LONG NumColours,BYTE TrueColour);
  51. extern struct Palette *    GetPalette(struct Screen *Screen,struct Palette *Palette);
  52. extern VOID        LoadPalette(struct Screen *Screen,struct Palette *Palette,LONG NumColours);
  53. extern LONG        GetPaletteSize(struct Palette *Palette);
  54. extern BYTE        GetPaletteTriplet(struct Palette *Palette,UBYTE *Triplet,LONG Index);
  55. extern BYTE        SetPaletteTriplet(struct Palette *Palette,UBYTE R,UBYTE G,UBYTE B,LONG Index);
  56. extern ULONG        GetPaletteEntry(struct Palette *Palette,LONG Index);
  57. extern BYTE        SetPaletteEntry(struct Palette *Palette,ULONG Entry,LONG Index);
  58.  
  59.     /* In unvscomp.asm */
  60.  
  61. extern VOID __asm    decode_vkplane(register __a0 UBYTE *deltabyte,register __a2 PLANEPTR plane,register __a3 UWORD *ytable,register __d2 UWORD bytesperrow);
  62.  
  63.     /* Local, static routines. */
  64.  
  65. STATIC __inline VOID    UnPackRow(BYTE **SourcePtr,BYTE **DestinationPtr,register WORD DestinationBytes);
  66. STATIC __inline VOID    SetRIFF(struct BitMap *BitMap,struct AnimNode *Node,UWORD *LineTable);
  67. STATIC __inline VOID    SetBODY(struct BitMap *BitMap,struct AnimNode *Node);
  68.  
  69. STATIC BYTE __regargs    GetBitMapHeader(struct AnimNode *Node,BitMapHeader *Header);
  70. STATIC BYTE __regargs    GetAnimationHeader(struct AnimNode *Node,AnimationHeader *Header);
  71. STATIC BYTE __regargs    GetColourMap(struct AnimNode *Node,UBYTE *Palette,LONG Size);
  72. STATIC VOID __regargs    DeleteAnimNode(struct AnimNode *Node);
  73.  
  74.     /* Exported routines. */
  75.  
  76. VOID            DeleteAnim(struct MinList *List);
  77. struct MinList *    LoadAnim(STRPTR Name);
  78. LONG            ValidateAnim(struct MinList *List,struct Screen *Screen);
  79. BYTE            PlayAnim(struct MinList *List,struct Screen *Screen,BYTE (*CheckAbort)(VOID));
  80.  
  81.  
  82.     /* UnPackRow(BYTE **SourcePtr,BYTE **DestinationPtr,register WORD DestinationBytes):
  83.      *
  84.      *    CmpByteRun unpacker, based on original EA IFF code.
  85.      */
  86.  
  87. STATIC __inline VOID
  88. UnPackRow(BYTE **SourcePtr,BYTE **DestinationPtr,register WORD DestinationBytes)
  89. {
  90.     register BYTE    *Source        = *SourcePtr,
  91.             *Destination    = *DestinationPtr,
  92.             Char;
  93.     register WORD    Count;
  94.  
  95.     while(DestinationBytes > 0)
  96.     {
  97.         if((Count = *Source++) >= 0)
  98.         {
  99.             Count++;
  100.  
  101.             if((DestinationBytes -= Count) < 0)
  102.                 break;
  103.             else
  104.             {
  105.                 do
  106.                     *Destination++ = *Source++;
  107.                 while(--Count);
  108.             }
  109.         }
  110.         else
  111.         {
  112.             if(Count != (WORD)(-128))
  113.             {
  114.                 Count = -Count + 1;
  115.  
  116.                 if((DestinationBytes -= Count) < 0)
  117.                     break;
  118.                 else
  119.                 {
  120.                     Char = *Source++;
  121.  
  122.                     do
  123.                         *Destination++ = Char;
  124.                     while(--Count);
  125.                 }
  126.             }
  127.         }
  128.     }
  129.  
  130.     *SourcePtr        = Source;
  131.     *DestinationPtr        = Destination;
  132. }
  133.  
  134.     /* SetRIFF(struct BitMap *BitMap,struct AnimNode *Node,UWORD *LineTable):
  135.      *
  136.      *    Unpack RIFF style delta data.
  137.      */
  138.  
  139. STATIC __inline VOID
  140. SetRIFF(struct BitMap *BitMap,struct AnimNode *Node,UWORD *LineTable)
  141. {
  142.     register LONG    *DeltaData = (LONG *)Node -> Body,
  143.              i;
  144.  
  145.         /* Run down the planes... */
  146.  
  147.     for(i = 0 ; i < BitMap -> Depth ; i++)
  148.     {
  149.             /* Any data to process? If so, unpack it. */
  150.  
  151.         if(DeltaData[i])
  152.             decode_vkplane((UBYTE *)DeltaData + DeltaData[i],BitMap -> Planes[i],LineTable,BitMap -> BytesPerRow);
  153.     }
  154. }
  155.  
  156.     /* SetBODY(struct BitMap *BitMap,struct AnimNode *Node):
  157.      *
  158.      *    Unpack CmpByteRun data.
  159.      */
  160.  
  161. STATIC __inline VOID
  162. SetBODY(struct BitMap *BitMap,struct AnimNode *Node)
  163. {
  164.     PLANEPTR     Planes[8],
  165.             *Destination;
  166.     BYTE        *Source;
  167.     LONG         i,j;
  168.  
  169.         /* Copy the plane addresses, we will modify the pointers. */
  170.  
  171.     for(i = 0 ; i < BitMap -> Depth ; i++)
  172.         Planes[i] = BitMap -> Planes[i];
  173.  
  174.         /* Copy the data pointer, this will be modified as well. */
  175.  
  176.     Source = (BYTE *)Node -> Body;
  177.  
  178.         /* Run down the rows... */
  179.  
  180.     for(i = 0 ; i < BitMap -> Rows ; i++)
  181.     {
  182.             /* Run down the planes... */
  183.  
  184.         for(j = 0 ; j < BitMap -> Depth ; j++)
  185.         {
  186.                 /* Remember the address. */
  187.  
  188.             Destination = &Planes[j];
  189.  
  190.                 /* Unpack the data. */
  191.  
  192.             UnPackRow(&Source,Destination,BitMap -> BytesPerRow);
  193.         }
  194.     }
  195. }
  196.  
  197.     /* GetBitMapHeader(struct AnimNode *Node,BitMapHeader *Header):
  198.      *
  199.      *    Attach a bitmap header to an animnode.
  200.      */
  201.  
  202. STATIC BYTE __regargs
  203. GetBitMapHeader(struct AnimNode *Node,BitMapHeader *Header)
  204. {
  205.     if(Node -> BitMapHeader = (BitMapHeader *)AllocVec(sizeof(BitMapHeader),MEMF_ANY))
  206.     {
  207.         CopyMem(Header,Node -> BitMapHeader,sizeof(BitMapHeader));
  208.  
  209.         return(TRUE);
  210.     }
  211.     else
  212.         return(FALSE);
  213. }
  214.  
  215.     /* GetAnimationHeader(struct AnimNode *Node,AnimationHeader *Header):
  216.      *
  217.      *    Attach and animation header to an animnode.
  218.      */
  219.  
  220. STATIC BYTE __regargs
  221. GetAnimationHeader(struct AnimNode *Node,AnimationHeader *Header)
  222. {
  223.     if(Node -> AnimationHeader = (AnimationHeader *)AllocVec(sizeof(AnimationHeader),MEMF_ANY))
  224.     {
  225.         CopyMem(Header,Node -> AnimationHeader,sizeof(AnimationHeader));
  226.  
  227.         return(TRUE);
  228.     }
  229.     else
  230.         return(FALSE);
  231. }
  232.  
  233.     /* GetColourMap(struct AnimNode *Node,UBYTE *Palette,LONG Size):
  234.      *
  235.      *    Attach a colour map to an animnode.
  236.      */
  237.  
  238. STATIC BYTE __regargs
  239. GetColourMap(struct AnimNode *Node,UBYTE *Palette,LONG Size)
  240. {
  241.         /* Determine number of palette entries. */
  242.  
  243.     LONG Count = Size / 3;
  244.  
  245.         /* Allocate a palette. */
  246.  
  247.     if(Node -> Palette = AllocPalette(Count,Count == 256))
  248.     {
  249.         LONG    R,G,B,
  250.             i;
  251.  
  252.             /* Eight bits? */
  253.  
  254.         if(Count == 256)
  255.         {
  256.                 /* Run down the table, setting the eight bit triplets. */
  257.  
  258.             for(i = 0 ; i < Count ; i++)
  259.             {
  260.                 R = *Palette++;
  261.                 G = *Palette++;
  262.                 B = *Palette++;
  263.  
  264.                 SetPaletteTriplet(Node -> Palette,R,G,B,i);
  265.             }
  266.         }
  267.         else
  268.         {
  269.                 /* Run down the table, setting the four bit triplets. */
  270.  
  271.             for(i = 0 ; i < Count ; i++)
  272.             {
  273.                 R = ((*Palette++) >> 4) & 0xF;
  274.                 G = ((*Palette++) >> 4) & 0xF;
  275.                 B = ((*Palette++) >> 4) & 0xF;
  276.  
  277.                 SetPaletteTriplet(Node -> Palette,R,G,B,i);
  278.             }
  279.         }
  280.  
  281.         return(TRUE);
  282.     }
  283.     else
  284.         return(FALSE);
  285. }
  286.     /* DeleteAnimNode(struct AnimNode *Node):
  287.      *
  288.      *    Free an animation list node.
  289.      */
  290.  
  291. STATIC VOID __regargs
  292. DeleteAnimNode(struct AnimNode *Node)
  293. {
  294.     if(Node -> BitMapHeader)
  295.         FreeVec(Node -> BitMapHeader);
  296.  
  297.     if(Node -> AnimationHeader)
  298.         FreeVec(Node -> AnimationHeader);
  299.  
  300.     if(Node -> Body)
  301.         FreeVec(Node -> Body);
  302.  
  303.     if(Node -> Palette)
  304.         FreePalette(Node -> Palette);
  305.  
  306.     FreeVec(Node);
  307. }
  308.  
  309.     /* DeleteAnim(struct MinList *List):
  310.      *
  311.      *    Delete the contents of an entire animation list.
  312.      */
  313.  
  314. VOID
  315. DeleteAnim(struct MinList *List)
  316. {
  317.     struct AnimNode    *Node,
  318.             *Next;
  319.  
  320.         /* Pick up the first node in the list. */
  321.  
  322.     Node = (struct AnimNode *)List -> mlh_Head;
  323.  
  324.         /* Run down the list... */
  325.  
  326.     while(Next = (struct AnimNode *)Node -> Node . mln_Succ)
  327.     {
  328.             /* Free the node. */
  329.  
  330.         DeleteAnimNode(Node);
  331.  
  332.             /* Skip to the next. */
  333.  
  334.         Node = Next;
  335.     }
  336.  
  337.         /* Remove the list itself. */
  338.  
  339.     FreeVec(List);
  340. }
  341.  
  342.     /* LoadAnim(STRPTR Name):
  343.      *
  344.      *    Load an ANIM5 animation file, creating a list suitable for
  345.      *    submitting to PlayAnim() or ValidateAnim().
  346.      */
  347.  
  348. struct MinList *
  349. LoadAnim(STRPTR Name)
  350. {
  351.         /* Data we will pick up on the fly. */
  352.  
  353.     STATIC ULONG Properties[2 * 4] =
  354.     {
  355.         ID_ILBM,ID_BMHD,
  356.         ID_ILBM,ID_ANHD,
  357.         ID_ILBM,ID_CAMG,
  358.         ID_ILBM,ID_CMAP
  359.     };
  360.  
  361.         /* Image and delta data. */
  362.  
  363.     STATIC ULONG Stops[2 * 2] =
  364.     {
  365.         ID_ILBM,ID_BODY,
  366.         ID_ILBM,ID_DLTA
  367.     };
  368.  
  369.     struct MinList *List;
  370.  
  371.         /* Allocate the body list. */
  372.  
  373.     if(List = (struct MinList *)AllocVec(sizeof(struct MinList),MEMF_ANY))
  374.     {
  375.         struct IFFHandle    *Handle;
  376.         BYTE             Success = TRUE;
  377.  
  378.             /* Initialize the list header. */
  379.  
  380.         NewList((struct List *)List);
  381.  
  382.             /* Allocate an IFF handle. */
  383.  
  384.         if(Handle = AllocIFF())
  385.         {
  386.                 /* Open the file for reading. */
  387.  
  388.             if(Handle -> iff_Stream = Open(Name,MODE_OLDFILE))
  389.             {
  390.                     /* Make it known as a dos file. */
  391.  
  392.                 InitIFFasDOS(Handle);
  393.  
  394.                     /* Open the file for reading. */
  395.  
  396.                 if(!OpenIFF(Handle,IFFF_READ))
  397.                 {
  398.                         /* Remember the properties to store. */
  399.  
  400.                     if(!PropChunks(Handle,Properties,4))
  401.                     {
  402.                             /* Remember the chunks to stop at. */
  403.  
  404.                         if(!StopChunks(Handle,Stops,2))
  405.                         {
  406.                             struct StoredProperty    *Prop;
  407.                             struct ContextNode    *Top;
  408.  
  409.                                 /* Start scanning... */
  410.  
  411.                             while(Success && !ParseIFF(Handle,IFFPARSE_SCAN))
  412.                             {
  413.                                     /* Pick up the topmost chunk. */
  414.  
  415.                                 if(Top = CurrentChunk(Handle))
  416.                                 {
  417.                                     struct AnimNode *Node;
  418.  
  419.                                         /* Allocate a new node. */
  420.  
  421.                                     if(Node = AllocVec(sizeof(struct AnimNode),MEMF_ANY | MEMF_CLEAR))
  422.                                     {
  423.                                             /* Add it to the list. */
  424.  
  425.                                         AddTail((struct List *)List,(struct Node *)Node);
  426.  
  427.                                             /* Add the bitmap header. */
  428.  
  429.                                         if(Prop = FindProp(Handle,ID_ILBM,ID_BMHD))
  430.                                         {
  431.                                             if(!GetBitMapHeader(Node,(BitMapHeader *)Prop -> sp_Data))
  432.                                             {
  433.                                                 Success = FALSE;
  434.                                                 break;
  435.                                             }
  436.                                         }
  437.  
  438.                                             /* Add the animation header. */
  439.  
  440.                                         if(Prop = FindProp(Handle,ID_ILBM,ID_ANHD))
  441.                                         {
  442.                                             if(!GetAnimationHeader(Node,(AnimationHeader *)Prop -> sp_Data))
  443.                                             {
  444.                                                 Success = FALSE;
  445.                                                 break;
  446.                                             }
  447.                                         }
  448.  
  449.                                             /* Add the display mode information. */
  450.  
  451.                                         if(Prop = FindProp(Handle,ID_ILBM,ID_CAMG))
  452.                                         {
  453.                                             Node -> ViewModes    = &Node -> Modes;
  454.                                             Node -> Modes        = *(ULONG *)Prop -> sp_Data;
  455.                                         }
  456.  
  457.                                             /* Add the colour map information. */
  458.  
  459.                                         if(Prop = FindProp(Handle,ID_ILBM,ID_CMAP))
  460.                                         {
  461.                                             if(!GetColourMap(Node,(UBYTE *)Prop -> sp_Data,Prop -> sp_Size))
  462.                                             {
  463.                                                 Success = FALSE;
  464.                                                 break;
  465.                                             }
  466.                                         }
  467.  
  468.                                             /* Now we are about the read the BODY or the DLTA information,
  469.                                              * but not both.
  470.                                              */
  471.  
  472.                                         if(Node -> Body || (Top -> cn_ID == ID_BODY && !Node -> BitMapHeader) || (Top -> cn_ID == ID_DLTA && !Node -> AnimationHeader))
  473.                                         {
  474.                                             Success = FALSE;
  475.                                             break;
  476.                                         }
  477.  
  478.                                             /* Allocate BODY or DLTA data, the animation header will
  479.                                              * provide the necessary information.
  480.                                              */
  481.  
  482.                                         if(Node -> Body = AllocVec(Top -> cn_Size,MEMF_ANY))
  483.                                         {
  484.                                             if(ReadChunkBytes(Handle,Node -> Body,Top -> cn_Size) != Top -> cn_Size)
  485.                                                 Success = FALSE;
  486.                                         }
  487.                                         else
  488.                                             Success = FALSE;
  489.                                     }
  490.                                     else
  491.                                         Success = FALSE;
  492.                                 }
  493.                             }
  494.                         }
  495.                     }
  496.  
  497.                         /* Close the handle. */
  498.  
  499.                     CloseIFF(Handle);
  500.                 }
  501.  
  502.                     /* Close the file. */
  503.  
  504.                 Close(Handle -> iff_Stream);
  505.             }
  506.  
  507.                 /* Free the handle data. */
  508.  
  509.             FreeIFF(Handle);
  510.         }
  511.  
  512.             /* Delete the animation list if anything went wrong. */
  513.  
  514.         if(!Success)
  515.         {
  516.             DeleteAnim(List);
  517.  
  518.             List = NULL;
  519.         }
  520.     }
  521.  
  522.     return(List);
  523. }
  524.  
  525.     /* ValidateAnim(struct MinList *List,struct Screen *Screen):
  526.      *
  527.      *    Validate the loaded animation and see if it fits both
  528.      *    the screen and the machine.
  529.      */
  530.  
  531. LONG
  532. ValidateAnim(struct MinList *List,struct Screen *Screen)
  533. {
  534.     struct AnimNode    *Node,
  535.             *Next;
  536.     BitMapHeader    *Header;
  537.     LONG         Frames = 0;
  538.  
  539.         /* Is there any data? */
  540.  
  541.     Node = (struct AnimNode *)List -> mlh_Head;
  542.  
  543.     if(Node -> Node . mln_Succ)
  544.     {
  545.             /* We _need_ a bitmap header. */
  546.  
  547.         if(!Node -> BitMapHeader)
  548.             return(ANIMERR_WRONG_SEQUENCE);
  549.         else
  550.             Header = Node -> BitMapHeader;
  551.     }
  552.     else
  553.         return(ANIMERR_NO_ANIM);
  554.  
  555.         /* Now scan the list... */
  556.  
  557.     while(Next = (struct AnimNode *)Node -> Node . mln_Succ)
  558.     {
  559.             /* Is the display mode available? */
  560.  
  561.         if(Node -> ViewModes)
  562.         {
  563.             if(ModeNotAvailable(*Node -> ViewModes))
  564.                 return(ANIMERR_WRONG_MODE);
  565.         }
  566.  
  567.             /* Is the image too `deep'? */
  568.  
  569.         if(Node -> BitMapHeader)
  570.         {
  571.             if(Node -> BitMapHeader -> nPlanes > 5 && !Is39)
  572.                 return(ANIMERR_WRONG_MODE);
  573.         }
  574.  
  575.             /* No delta or image data available? */
  576.  
  577.         if(!Node -> Body)
  578.             return(ANIMERR_NO_BODY);
  579.  
  580.             /* Animation header available? */
  581.  
  582.         if(Node -> AnimationHeader)
  583.         {
  584.                 /* Only type 5 animations are supported
  585.                  * so far...
  586.                  */
  587.  
  588.             if(Node -> AnimationHeader -> operation != 5)
  589.                 return(ANIMERR_WRONG_OPERATION);
  590.  
  591.                 /* No masking, please. */
  592.  
  593.             if(Node -> AnimationHeader -> mask)
  594.                 return(ANIMERR_MASKING);
  595.  
  596.             Frames++;
  597.         }
  598.  
  599.             /* Bitmap header available? */
  600.  
  601.         if(Node -> BitMapHeader)
  602.         {
  603.                 /* Strange image information? */
  604.  
  605.             if(Node -> BitMapHeader -> nPlanes < 1 || Node -> BitMapHeader -> nPlanes > 8 || !Node -> BitMapHeader -> w || !Node -> BitMapHeader -> h)
  606.                 return(ANIMERR_IMAGE);
  607.  
  608.                 /* No masking, please. */
  609.  
  610.             if(Node -> BitMapHeader -> masking)
  611.                 return(ANIMERR_MASKING);
  612.  
  613.                 /* The image _has_ to be compressed! */
  614.  
  615.             if(Node -> BitMapHeader -> compression != 1)
  616.                 return(ANIMERR_COMPRESSION);
  617.  
  618.                 /* Does it fit the screen? */
  619.  
  620.             if(Node -> BitMapHeader -> w != Screen -> Width || Node -> BitMapHeader -> h != Screen -> Height || Node -> BitMapHeader -> nPlanes != Screen -> RastPort . BitMap -> Depth)
  621.                 return(ANIMERR_WRONG_SIZE);
  622.  
  623.             Frames++;
  624.         }
  625.  
  626.         Node = Next;
  627.     }
  628.  
  629.         /* There should be at least two frames. */
  630.  
  631.     if(Frames < 2)
  632.         return(ANIMERR_NO_ANIM);
  633.     else
  634.     {
  635.         if(!Header)
  636.             return(ANIMERR_NO_HEADER);
  637.         else
  638.             return(0);
  639.     }
  640. }
  641.  
  642.     /* PlayAnim(struct MinList *List,struct Screen *Screen,BYTE (*CheckAbort)(VOID)):
  643.      *
  644.      *    Replay an animation.
  645.      */
  646.  
  647. BYTE
  648. PlayAnim(struct MinList *List,struct Screen *Screen,BYTE (*CheckAbort)(VOID))
  649. {
  650.     struct DBI    *Info;
  651.     BYTE         Result = FALSE;
  652.  
  653.         /* Allocate double-buffering information. */
  654.  
  655.     if(Info = AllocDBI(Screen))
  656.     {
  657.         UWORD *LineTable;
  658.  
  659.             /* Set up the line byte modulo table. */
  660.  
  661.         if(LineTable = (UWORD *)AllocVec(sizeof(UWORD) * Screen -> Height,MEMF_ANY))
  662.         {
  663.             struct AnimNode        *Node,
  664.                         *Next;
  665.             struct BitMap        *BitMap;
  666.             BYTE             Done = FALSE;
  667.             UWORD             Count,
  668.                          i;
  669.  
  670.                 /* Get the bitmap to render into. */
  671.  
  672.             BitMap = GetDBI(Info);
  673.  
  674.                 /* Set up the table information. */
  675.  
  676.             for(i = Count = 0 ; i < BitMap -> Rows ; i++)
  677.             {
  678.                 LineTable[i] = Count;
  679.  
  680.                 Count += BitMap -> BytesPerRow;
  681.             }
  682.  
  683.                 /* Run the loop... */
  684.  
  685.             do
  686.             {
  687.                     /* Get the first list entry, this
  688.                      * should be the first image.
  689.                      */
  690.  
  691.                 Node = (struct AnimNode *)List -> mlh_Head;
  692.  
  693.                     /* Run down the list... */
  694.  
  695.                 while(Next = (struct AnimNode *)Node -> Node . mln_Succ)
  696.                 {
  697.                         /* Get the bitmap to render into. */
  698.  
  699.                     BitMap = GetDBI(Info);
  700.  
  701.                         /* Any palette to set? */
  702.  
  703.                     if(Node -> Palette)
  704.                         PaletteDBI(Info,Node -> Palette);
  705.  
  706.                         /* Delta data to unpack? */
  707.  
  708.                     if(Node -> AnimationHeader)
  709.                     {
  710.                             /* Any inter-frame delay? */
  711.  
  712.                         if(Node -> AnimationHeader -> reltime)
  713.                         {
  714.                                 /* Start the timer... */
  715.  
  716.                             StartDBI(Info,Node -> AnimationHeader -> reltime);
  717.  
  718.                                 /* Unpack the delta data. */
  719.  
  720.                             SetRIFF(BitMap,Node,LineTable);
  721.  
  722.                                 /* Wait for timer to elapse. */
  723.  
  724.                             WaitDBI(Info);
  725.                         }
  726.                         else
  727.                             SetRIFF(BitMap,Node,LineTable);
  728.                     }
  729.                     else
  730.                         SetBODY(BitMap,Node);
  731.  
  732.                         /* Swap in the bitmap just rendered. */
  733.  
  734.                     SwapDBI(Info,TRUE);
  735.  
  736.                         /* Check for abort action. */
  737.  
  738.                     if((*CheckAbort)())
  739.                     {
  740.                         Done = TRUE;
  741.                         break;
  742.                     }
  743.  
  744.                         /* Skip to the next frame. */
  745.  
  746.                     Node = Next;
  747.                 }
  748.  
  749.                     /* Check for abort action. */
  750.  
  751.                 if((*CheckAbort)())
  752.                     Done = TRUE;
  753.             }
  754.             while(!Done);
  755.  
  756.                 /* Free the line modulo table. */
  757.  
  758.             FreeVec(LineTable);
  759.  
  760.                 /* We are successful so far. */
  761.  
  762.             Result = TRUE;
  763.         }
  764.  
  765.             /* Free the double-buffering information. */
  766.  
  767.         FreeDBI(Info);
  768.     }
  769.  
  770.     return(Result);
  771. }
  772.